import java.util.Map;
import java.util.Set;
import java.util.HashMap;
import java.util.HashSet;

/**
 * 习题类单元测试
 * 对ExerciseSet类的所有功能进行系统性测试
 * 
 * @author Test Designer
 * @version 1.0
 */
public class ExerciseSetTest {
    private static int testCount = 0;  // 测试计数器
    private static int passCount = 0;  // 通过计数器
    
    /**
     * 主测试方法
     */
    public static void main(String[] args) {
        System.out.println("===== 习题类（ExerciseSet）单元测试 =====\n");
        
        // 测试构造函数
        testConstructor();
        
        // 测试生成习题功能
        testGenerateExercises();
        
        // 测试添加算式功能
        testAddExpression();
        
        // 测试统计功能
        testStatistics();
        
        // 测试有效性检查
        testValidation();
        
        // 测试显示功能
        testDisplay();
        
        // 测试边界值情况
        testBoundaryValues();
        
        // 测试重复性检查
        testUniqueness();
        
        // 输出测试结果
        System.out.println("\n===== 测试结果统计 =====");
        System.out.println("总测试数: " + testCount);
        System.out.println("通过数: " + passCount);
        System.out.println("失败数: " + (testCount - passCount));
        System.out.println("通过率: " + String.format("%.1f%%", (double)passCount/testCount*100));
        
        if (passCount == testCount) {
            System.out.println("\n🎉 所有测试通过！");
        } else {
            System.out.println("\n❌ 有测试失败，需要检查代码！");
        }
    }
    
    /**
     * 记录测试结果
     */
    private static void recordTestResult(String testName, boolean passed) {
        testCount++;
        if (passed) {
            passCount++;
            System.out.println("✅ 通过: " + testName);
        } else {
            System.out.println("❌ 失败: " + testName);
        }
    }
    
    /**
     * 测试构造函数
     */
    private static void testConstructor() {
        System.out.println("1. 测试构造函数:");
        
        // 测试默认构造函数
        ExerciseSet set1 = new ExerciseSet();
        boolean test1 = set1.getTotalCount() == 0 && set1.getExpressions().isEmpty();
        recordTestResult("默认构造函数初始状态", test1);
        
        // 测试带参数构造函数
        ExerciseSet set2 = new ExerciseSet(20);
        boolean test2 = set2.getTotalCount() == 0 && set2.getExpressions().isEmpty();
        recordTestResult("带参数构造函数初始状态", test2);
        
        // 测试带随机种子构造函数
        ExerciseSet set3 = new ExerciseSet(30, 12345L);
        boolean test3 = set3.getTotalCount() == 0 && set3.getExpressions().isEmpty();
        recordTestResult("带随机种子构造函数初始状态", test3);
        
        System.out.println();
    }
    
    /**
     * 测试生成习题功能
     */
    private static void testGenerateExercises() {
        System.out.println("2. 测试生成习题功能:");
        
        // 使用固定随机种子确保可重复性
        ExerciseSet set = new ExerciseSet(50, 12345L);
        set.generateExercises();
        
        // 检查生成数量
        boolean test1 = set.getTotalCount() == 50;
        recordTestResult("生成指定数量的算式", test1);
        
        // 检查所有算式都有效
        boolean test2 = checkAllValid(set);
        recordTestResult("所有生成的算式都有效", test2);
        
        // 检查无重复
        boolean test3 = checkNoDuplicates(set);
        recordTestResult("生成的算式无重复", test3);
        
        // 检查加法比例
        double additionRatio = (double) set.getAdditionCount() / set.getTotalCount();
        boolean test4 = additionRatio >= 0.4; // 至少40%
        recordTestResult("加法比例控制", test4);
        
        // 检查减法比例
        double subtractionRatio = (double) set.getSubtractionCount() / set.getTotalCount();
        boolean test5 = subtractionRatio >= 0.3; // 最多60%
        recordTestResult("减法比例控制", test5);
        
        System.out.println();
    }
    
    /**
     * 测试添加算式功能
     */
    private static void testAddExpression() {
        System.out.println("3. 测试添加算式功能:");
        
        ExerciseSet set = new ExerciseSet();
        
        // 测试添加有效的加法算式
        Expression exp1 = new Expression(30, '+', 20);
        boolean test1 = set.addExpression(exp1);
        recordTestResult("添加有效加法算式", test1);
        
        // 测试添加有效的减法算式
        Expression exp2 = new Expression(80, '-', 30);
        boolean test2 = set.addExpression(exp2);
        recordTestResult("添加有效减法算式", test2);
        
        // 测试添加重复算式
        Expression exp3 = new Expression(30, '+', 20);
        boolean test3 = !set.addExpression(exp3);
        recordTestResult("添加重复算式失败", test3);
        
        // 测试添加无效算式（结果>100的加法）
        Expression exp4 = new Expression(70, '+', 40);
        boolean test4 = set.addExpression(exp4); // 应该允许添加，但无效
        recordTestResult("添加无效加法算式", test4);
        
        // 测试添加null
        boolean test5 = !set.addExpression(null);
        recordTestResult("添加null算式失败", test5);
        
        // 检查总数
        boolean test6 = set.getTotalCount() == 3;
        recordTestResult("添加后总数正确", test6);
        
        System.out.println();
    }
    
    /**
     * 测试统计功能
     */
    private static void testStatistics() {
        System.out.println("4. 测试统计功能:");
        
        ExerciseSet set = new ExerciseSet();
        
        // 添加一些算式
        set.addExpression(new Expression(20, '+', 30));
        set.addExpression(new Expression(50, '-', 20));
        set.addExpression(new Expression(40, '+', 25));
        set.addExpression(new Expression(60, '-', 15));
        
        Map<String, Integer> stats = set.calculateStatistics();
        
        // 检查总数
        boolean test1 = stats.get("total") == 4;
        recordTestResult("统计总数", test1);
        
        // 检查加法数量
        boolean test2 = stats.get("addition") == 2;
        recordTestResult("统计加法数量", test2);
        
        // 检查减法数量
        boolean test3 = stats.get("subtraction") == 2;
        recordTestResult("统计减法数量", test3);
        
        // 检查有效数量
        boolean test4 = stats.get("valid") == 4;
        recordTestResult("统计有效数量", test4);
        
        // 检查加法比例
        boolean test5 = stats.get("additionRatio") == 50;
        recordTestResult("统计加法比例", test5);
        
        System.out.println();
    }
    
    /**
     * 测试有效性检查
     */
    private static void testValidation() {
        System.out.println("5. 测试有效性检查:");
        
        ExerciseSet set = new ExerciseSet();
        
        // 测试有效加法
        boolean test1 = set.isValidAddition(30, 40);
        recordTestResult("有效加法检查", test1);
        
        // 测试无效加法
        boolean test2 = !set.isValidAddition(60, 50);
        recordTestResult("无效加法检查", test2);
        
        // 测试有效减法
        boolean test3 = set.isValidSubtraction(70, 30);
        recordTestResult("有效减法检查", test3);
        
        // 测试无效减法
        boolean test4 = !set.isValidSubtraction(20, 50);
        recordTestResult("无效减法检查", test4);
        
        System.out.println();
    }
    
    /**
     * 测试显示功能
     */
    private static void testDisplay() {
        System.out.println("6. 测试显示功能:");
        
        ExerciseSet set = new ExerciseSet();
        
        // 添加一些算式进行显示测试
        set.addExpression(new Expression(20, '+', 30));
        set.addExpression(new Expression(50, '-', 20));
        set.addExpression(new Expression(40, '+', 25));
        
        // 测试display方法（不抛出异常）
        try {
            set.display();
            boolean test1 = true;
            recordTestResult("display方法正常执行", test1);
        } catch (Exception e) {
            recordTestResult("display方法正常执行", false);
        }
        
        // 测试displayFormatted方法（不抛出异常）
        try {
            set.displayFormatted();
            boolean test2 = true;
            recordTestResult("displayFormatted方法正常执行", test2);
        } catch (Exception e) {
            recordTestResult("displayFormatted方法正常执行", false);
        }
        
        // 测试toString方法
        String str = set.toString();
        boolean test3 = str != null && str.contains("ExerciseSet");
        recordTestResult("toString方法返回正确格式", test3);
        
        System.out.println();
    }
    
    /**
     * 测试边界值情况
     */
    private static void testBoundaryValues() {
        System.out.println("7. 测试边界值情况:");
        
        // 测试生成0道题
        ExerciseSet set1 = new ExerciseSet(0, 12345L);
        set1.generateExercises();
        boolean test1 = set1.getTotalCount() == 0;
        recordTestResult("生成0道题", test1);
        
        // 测试生成1道题
        ExerciseSet set2 = new ExerciseSet(1, 12345L);
        set2.generateExercises();
        boolean test2 = set2.getTotalCount() == 1;
        recordTestResult("生成1道题", test2);
        
        // 测试生成大量题目（100道）
        ExerciseSet set3 = new ExerciseSet(100, 12345L);
        set3.generateExercises();
        boolean test3 = set3.getTotalCount() == 100 && checkAllValid(set3);
        recordTestResult("生成100道题", test3);
        
        // 测试空集合的统计
        Map<String, Integer> stats = set1.calculateStatistics();
        boolean test4 = stats.get("total") == 0 && stats.get("addition") == 0;
        recordTestResult("空集合统计", test4);
        
        // 测试边界值加法
        ExerciseSet set4 = new ExerciseSet();
        set4.addExpression(new Expression(100, '+', 0));  // 结果=100
        boolean test5 = set4.getExpressions().get(0).isValid();
        recordTestResult("加法边界值：100+0", test5);
        
        // 测试边界值减法
        set4.addExpression(new Expression(0, '-', 0));    // 结果=0
        boolean test6 = set4.getExpressions().get(1).isValid();
        recordTestResult("减法边界值：0-0", test6);
        
        System.out.println();
    }
    
    /**
     * 测试重复性检查
     */
    private static void testUniqueness() {
        System.out.println("8. 测试重复性检查:");
        
        ExerciseSet set = new ExerciseSet();
        
        // 测试hasExpression方法
        Expression exp1 = new Expression(30, '+', 20);
        set.addExpression(exp1);
        boolean test1 = set.hasExpression(exp1);
        recordTestResult("检查已存在算式", test1);
        
        Expression exp2 = new Expression(25, '+', 25);
        boolean test2 = !set.hasExpression(exp2);
        recordTestResult("检查不存在算式", test2);
        
        // 测试大规模生成的重复性
        ExerciseSet largeSet = new ExerciseSet(200, 12345L);
        largeSet.generateExercises();
        boolean test3 = checkNoDuplicates(largeSet);
        recordTestResult("大规模生成无重复", test3);
        
        System.out.println();
    }
    
    /**
     * 检查集合中所有算式是否都有效
     */
    private static boolean checkAllValid(ExerciseSet set) {
        for (Expression exp : set.getExpressions()) {
            if (!exp.isValid()) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 检查集合中是否有重复算式
     */
    private static boolean checkNoDuplicates(ExerciseSet set) {
        Set<String> expressionSet = new HashSet<>();
        for (Expression exp : set.getExpressions()) {
            String key = exp.formatExpression();
            if (expressionSet.contains(key)) {
                return false;
            }
            expressionSet.add(key);
        }
        return true;
    }
}